/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.editor;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import javax.swing.text.BadLocationException;
import javax.swing.text.Segment;
/**
* Encapsulation of a special static segment used
* by syntax scanners. Unfortunately document cache cannot
* guarantee that its fragment(s) will hold more than one character
* at the time so syntax scanning cannot be done by finder. Instead
* all the syntax analyzes are done over the syntax segment's data.
* Although it's shared across all instances of editors
* the loads into it should be fast as they are done from cache fragments
* by arraycopy() method.
* The syntax segment is separated into the slots because there
* can be more scanning necessary at one time.
* All the scanning must be done
*
* @author Miloslav Metelka
* @version 1.00
*/
class SyntaxSeg extends Segment {
private static final char[] EMPTY_CHAR_ARRAY = new char[0];
private static final int MAX_SLOT_COUNT = 100;
private static final int REALLOC_INCREMENT = 2048;
/**
* @associates Slot
*/
private static ArrayList slotList = new ArrayList();
static synchronized Slot getFreeSlot() {
int cnt = slotList.size();
return (cnt > 0) ? (Slot)slotList.remove(cnt - 1) : new Slot();
}
static synchronized void releaseSlot(Slot slot) {
slotList.add(slot);
}
/** From this position on, the data in syntax segment must be marked
* invalid.
*/
static synchronized void invalidate(BaseDocument doc, int pos) {
int cnt = slotList.size();
for (int i = 0; i < cnt; i++) {
((Slot)slotList.get(i)).invalidate(doc, pos);
}
}
static class Slot extends Segment {
/** Document from which the data in syntax segment come from */
WeakReference segDocRef = new WeakReference(null);
/** Begining of valid data in syntax segment */
int segPos;
/** Begining of valid data in syntax segment */
int segLen;
Slot() {
this.array = EMPTY_CHAR_ARRAY;
}
/** Load the syntax segment if necessary from some location in some
* document. For best performance there's no pos or len correctness
* checking. Therefore caller must guarantee the correctness.
* @return real length that was loaded (syntax segment has limitation
* in size)
*/
int load(BaseDocument doc, int pos, int len)
throws BadLocationException {
if (len <= 0) {
if (len == 0) {
count = 0;
return 0;
}
throw new Error("len=" + len); // Critical error NOI18N
}
BaseDocument segDoc = (BaseDocument)segDocRef.get();
boolean difDoc = (doc != segDoc);
if (difDoc) {
segDoc = doc;
segDocRef = new WeakReference(segDoc);
}
if (difDoc // different documents
|| pos < segPos // position too low
|| pos > segPos + segLen // position too high
|| pos - segPos + len > array.length
) { // wouldn't fit
// possibly realloc the array
if (len > array.length) {
char tmp[] = new char[len + REALLOC_INCREMENT];
array = tmp; // original data are not recopied
}
segPos = pos;
segLen = len;
doc.getChars(pos, array, 0, len); // read chars into array
} else { // inside array and will fit
int endSegPos = segPos + segLen;
int restLen = pos + len - endSegPos;
if (restLen > 0) { // not fully inside
doc.getChars(endSegPos, array, segLen, restLen);
segLen += restLen;
}
}
offset = pos - segPos;
count = len;
if (offset < 0 || len < 0) {
throw new Error("pos=" + pos + ", offset=" + offset // NOI18N
+ "len=" + len); // Critical error NOI18N
}
return len;
}
/** Is the area inside the segment? */
boolean isAreaInside(BaseDocument doc, int pos, int len) {
return (doc == (BaseDocument)segDocRef.get()
&& pos >= segPos && pos + len <= segPos + segLen);
}
/** Invalidate the slot if it contains the data from the given document.
* @param doc document in which the change occured
* @param pos position in the document where the change occured
*/
void invalidate(BaseDocument doc, int pos) {
if (doc == (BaseDocument)segDocRef.get()) {
if (pos < segPos) {
segLen = 0;
} else if (pos < segPos + segLen) {
segLen = pos - segPos;
}
}
}
}
}
/*
* Log
* 17 Gandalf 1.16 1/16/00 Miloslav Metelka
* 16 Gandalf 1.15 1/13/00 Miloslav Metelka
* 15 Gandalf 1.14 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 14 Gandalf 1.13 10/10/99 Miloslav Metelka
* 13 Gandalf 1.12 9/16/99 Miloslav Metelka
* 12 Gandalf 1.11 9/15/99 Miloslav Metelka
* 11 Gandalf 1.10 9/10/99 Miloslav Metelka
* 10 Gandalf 1.9 7/20/99 Miloslav Metelka
* 9 Gandalf 1.8 6/8/99 Miloslav Metelka
* 8 Gandalf 1.7 6/1/99 Miloslav Metelka
* 7 Gandalf 1.6 5/15/99 Miloslav Metelka fixes
* 6 Gandalf 1.5 5/13/99 Miloslav Metelka
* 5 Gandalf 1.4 5/5/99 Miloslav Metelka
* 4 Gandalf 1.3 4/23/99 Miloslav Metelka Undo added and internal
* improvements
* 3 Gandalf 1.2 4/8/99 Ian Formanek Removed debug prints
* 2 Gandalf 1.1 3/27/99 Miloslav Metelka
* 1 Gandalf 1.0 2/13/99 Miloslav Metelka
* $
*/